package com.singfan.common.util;

import com.singfan.common.SingFanException;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 加密工具类
 * Author: HanSongHe
 * Date: 2015-07-27 14:09
 * Desc:
 */
public class EncryptionUtil {

    private static final char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

    /**
     * MD5加密，如果要加密的字符串为空，则返回null。
     * @param text 要加密的字符串
     * @return 加密后的值
     */
    public static String md5(String text){
        String result = null;

        if(!StringUtil.isNullOrEmpty(text)){
            try {
                byte[] strTemp = text.getBytes();
                MessageDigest mdTemp = MessageDigest.getInstance("MD5");
                mdTemp.update(strTemp);
                byte[] md = mdTemp.digest();

                // 把密文转换成十六进制的字符串形式
                char str[] = new char[md.length * 2];
                int k = 0;
                for (byte b : md){
                    str[k++] = hexDigits[b >>> 4 & 0xf];
                    str[k++] = hexDigits[b & 0xf];
                }
                result = new String(str);
            }
            catch (NoSuchAlgorithmException ex) {
                throw new SingFanException(String.format("EncryptionUtil.md5() error: %s !", ex.getMessage()), ex);
            }
        }
        return result;
    }

    /**
     * RC4加密解密，如果要加密解密的data和key为空，则直接返回data。
     * @param data 要加密解密的值
     * @param key 秘钥
     * @return 运算后的值
     */
    public static byte[] rc4(byte[] data, String key){
        byte[] result = null;

        if(data != null && data.length > 0 && !StringUtil.isNullOrEmpty(key)){
            //初始化真正的加密key
            byte[] keyBytes = key.getBytes();
            byte realKey[] = new byte[256];
            for (int i = 0; i < 256; i++) {
                realKey[i] = (byte) i;
            }
            int index1 = 0;
            int index2 = 0;
            if (keyBytes.length > 0) {
                for (int i = 0; i < 256; i++) {
                    index2 = ((keyBytes[index1] & 0xff) + (realKey[i] & 0xff) + index2) & 0xff;
                    byte tmp = realKey[i];
                    realKey[i] = realKey[index2];
                    realKey[index2] = tmp;
                    index1 = (index1 + 1) % keyBytes.length;
                }

                //开始rc4运算
                int x = 0;
                int y = 0;
                int xorIndex;
                result = new byte[data.length];

                for (int i = 0; i < data.length; i++) {
                    x = (x + 1) & 0xff;
                    y = ((realKey[x] & 0xff) + y) & 0xff;
                    byte tmp = realKey[x];
                    realKey[x] = realKey[y];
                    realKey[y] = tmp;
                    xorIndex = ((realKey[x] & 0xff) + (realKey[y] & 0xff)) & 0xff;
                    result[i] = (byte) (data[i] ^ realKey[xorIndex]);
                }
            }
        }
        else{
            result = data;
        }

        return result;
    }

    /**
     * 加密字符串，如果要加密的text为空，则直接返回text。
     * @param text 字符串
     * @return 加密后的字符串
     */
    public static String base64Encode(String text){
        String result;

        if(!StringUtil.isNullOrEmpty(text)){
            result = new BASE64Encoder().encode(text.getBytes());
        }
        else{
            result = text;
        }

        return result;
    }

    /**
     * 解密字符串，如果要解密的text为空，则直接返回text。
     * @param text 加密过的字符串
     * @return 解密后的字符串
     */
    public static String base64Decode(String text){
        String result;

        if(!StringUtil.isNullOrEmpty(text)){
            try {
                result = new String(new BASE64Decoder().decodeBuffer(text));
            }
            catch (IOException ex) {
                throw new SingFanException(String.format("EncryptionUtil.base64Decode() error: %s !", ex.getMessage()), ex);
            }
        }
        else{
            result = text;
        }

        return result;
    }
}
